#pragma once

#include "IInterface.h"
#include "IModuleManager.h"

//////////////////////////////////////////////////////////////////////////
// CreateModule
#pragma warning(push)
#pragma warning(disable: 4311)

template<class Module, class Interface>
inline DWORD CreateModuleImpl()
{
#ifdef _AFX
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif

	Module* pModule = new Module;
	return (DWORD)static_cast<Interface*>(pModule);
}

#define ExportModule(ModuleClassName) \
	__declspec(dllexport) DWORD __stdcall CreateModule(void) { \
		return CreateModuleImpl<ModuleClassName, IModule>(); \
	}

#define ExportModuleInterface(ModuleClassName, InterfaceName) \
	__declspec(dllexport) DWORD  __stdcall CreateModule(void) { \
		return CreateModuleImpl<ModuleClassName, InterfaceName>(); \
	}

#pragma warning(pop)
//////////////////////////////////////////////////////////////////////////

class IModule : public IInterface
{
public:
	enum { ID = 'IMod'|'ule' };

public:
	virtual ~IModule() { }

public:
	virtual HRESULT Initialize(LPCTSTR* argv, int argc) = 0;

	virtual HRESULT Finalize() = 0;

	virtual HRESULT SetModuleManager(IModuleManager* pIModuleManager) = 0;

	virtual HRESULT GetModuleManager(IModuleManager** ppIModuleManager) = 0;

	virtual int GetID() = 0;

	template<class Interface>
	inline Interface* QueryModuleInterface(int mid)
	{
		IModuleManager* pIModuleManager = NULL;
		HRESULT hr = GetModuleManager(&pIModuleManager);
		if(pIModuleManager == NULL)
			return NULL;

		IModule* pIModule = NULL;
		hr = pIModuleManager->GetModule(mid, &pIModule);
		if(pIModule == NULL)
			return NULL;

		return pIModule->QI<Interface>();
	}

	using IInterface::QI;

	template<class Interface>
	inline Interface* QMI()
	{
		return QueryModuleInterface<Interface>(Interface::MID);
	}

	template<class Interface>
	inline Interface* QI(int mid)
	{
		return QueryModuleInterface<Interface>(mid);
	}

	template<class Interface>
	inline Interface* QMI(int mid)
	{
		return QueryModuleInterface<Interface>(mid);
	}
};

namespace detail
{

template<class IModuleTy,
		 class I1 = void, class I2 = void, class I3 = void, 
		 class I4 = void, class I5 = void, class I6 = void, 
		 class I7 = void, class I8 = void, class I9 = void
		>
class CModuleImpl : public IMultiInterface<IModuleTy, I1, I2, I3, I4, I5, I6, I7, I8, I9>
{
public:
	CModuleImpl() : m_pIModuleManager(NULL)
	{
	}

public:
	// Override INoAddRefInterface
	virtual ULONG Release()
	{
		delete this;
		return 0;
	}

public:
	// Override IModule
	virtual HRESULT Initialize(LPCTSTR* argv, int argc)
	{
		return S_OK;
	}

	virtual HRESULT Finalize()
	{
		return S_OK;
	}

	virtual HRESULT SetModuleManager(IModuleManager* pIModuleManager)
	{
		if(pIModuleManager == NULL)
			return E_POINTER;

		m_pIModuleManager = pIModuleManager;
		return S_OK;
	}

	virtual HRESULT GetModuleManager(IModuleManager** ppIModuleManager)
	{
		if(ppIModuleManager == NULL)
			return E_POINTER;

		*ppIModuleManager = m_pIModuleManager;
		return S_OK;
	}

	virtual int GetID()
	{
		return IModuleTy::MID;
	}

protected:
	IModuleManager* m_pIModuleManager;
};

} // end of namespace detail

template<class IModuleTy, class I1 = void, class I2 = void,
		 class I3 = void, class I4 = void, class I5 = void,
		 class I6 = void, class I7 = void, class I8 = void
		>
class CModuleImpl : public detail::CModuleImpl<IModuleTy, IModule, I1, I2, I3, I4, I5, I6, I7, I8>
{
public:
	virtual ~CModuleImpl()
	{
	}
};

typedef struct SShortcutKey* PShortcutKey;
typedef struct SShortcutKey
{
	bool ctrl;
	bool alt;
	bool shift;
	bool win;
	uchar key;
}const* LPShortcutKey;

union UVersion
{
	uint32 version;
	struct SVersion 
	{
		uint8 build;
		uint8 revision;
		uint8 minor;
		uint8 major;
	}num;
};

class IModule2 : public IInterfaceT<IModule>
{
public:
	enum { ID = 'IMod'|'ule2' };

public:
	virtual LPCTSTR GetName() = 0;
	virtual uint32 GetVersion() = 0;
	virtual LPShortcutKey GetShortcutKey() = 0;

	virtual bool ShowUI() = 0;
	virtual BOOL PreTranslateMessage(MSG*) = 0;
};

template<class IModuleTy, class I1 = void, class I2 = void,
		 class I3 = void, class I4 = void, class I5 = void,
		 class I6 = void, class I7 = void, class I8 = void
		>
class CModuleImpl2 : public detail::CModuleImpl<IModuleTy, IModule2, I1, I2, I3, I4, I5, I6, I7, I8>
{
public:
	// Override IModule2
	virtual LPCTSTR GetName()
	{
		return NULL;
	}

	virtual uint32 GetVersion()
	{
		return 0;
	}

	virtual LPShortcutKey GetShortcutKey()
	{
		return NULL;
	}

	virtual bool ShowUI()
	{
		return false;
	}

	virtual BOOL PreTranslateMessage(MSG*)
	{
		return FALSE;
	}
};
